package play;

import java.util.LinkedList;
import java.util.List;

public abstract class Scope extends Symbol {
    // 该 scope 中的成员，包括变量、方法、类等
    protected List<Symbol> symbols = new LinkedList<>();

    /**
     * 向 scope 中添加符号，同时设置好该符号的 enclosingScope
     * @param symbol 添加的符号
     */
    protected void addSymbol(Symbol symbol) {
        symbols.add(symbol);
        symbol.enclosingScope = this;
    }

    /**
     * 是否包含某个 Variable
     * @param name 变量名
     * @return 变量
     */
    protected Variable getVariable(String name) {
        return getVariable(this, name);
    }

    protected static Variable getVariable(Scope scope, String name) {
        for (Symbol s : scope.symbols) {
            if (s instanceof  Variable && s.name.equals(name)) {
                return (Variable) s;
            }
        }
        return null;
    }

    /**
     * 是否包含某个Function。
     * @param name name
     * @param paramTypes 参数类型。不允许为空。如果没有参数，需要传入一个空列表
     * @return 函数
     */
    protected Function getFunction(String name, List<Type> paramTypes) {
        return getFunction(this, name, paramTypes);
    }

    /**
     * 这是个静态方法，可以做为工具方法重用。避免类里要超找父类的情况。
     * @param scope 查找范围
     * @param name 名字
     * @param paramTypes 参数
     * @return 函数
     */
    protected static Function getFunction(Scope scope, String name, List<Type> paramTypes) {
        Function rtn = null;
        for (Symbol s : scope.symbols) {
            if (s instanceof Function && s.name.equals(name)) {
                Function function = (Function) s;
                if (function.matchParameterTypes(paramTypes)) {
                    rtn = function;
                    break;
                }
            }
        }
        return rtn;
    }

    /**
     * 获取一个函数类型的变量，匹配相应的参数类型
     * @param name 变量名
     * @param paramTypes 参数类型
     * @return 变量
     */
    protected Variable getFunctionVariable(String name, List<Type> paramTypes) {
        return getFunctionVariable(this, name, paramTypes);
    }

    protected static Variable getFunctionVariable(Scope scope, String name, List<Type> paramTypes) {
        Variable rtn = null;
        for (Symbol s : scope.symbols) {
            if (s instanceof Variable && ((Variable) s).type instanceof FunctionType && s.name.equals(name)) {
                Variable v = (Variable) s;
                FunctionType functionType = (FunctionType) v.type;
                if (functionType.matchParameterTypes(paramTypes)) {
                    rtn = v;
                    break;
                }
            }
        }
        return rtn;
    }

    /**
     * 是否包含某个 Class
     * @param name 类名
     * @return Class
     */
    protected Class getClass(String name) {
        return getClass(this, name);
    }

    protected static Class getClass(Scope scope, String name) {
        for (Symbol s : scope.symbols) {
            if (s instanceof Class && s.name.equals(name)) {
                return (Class) s;
            }
        }
        return null;
    }

    /**
     * 是否包含某个 Symbol
     * @param symbol 符号
     * @return bool
     */
    protected boolean containsSymbol(Symbol symbol) {
        return symbols.contains(symbol);
    }

    @Override
    public String toString() {
        return "Scope: " + name;
    }
}
